<?php

namespace common\service;

use common\exception\LogicException;
use common\model\ChatModel;
use common\model\ChatUserModel;
use common\model\FrequentContactsModel;
use common\model\TenantPositionModel;
use support\ErrorCode;
use support\SingletonTrait;
use think\Cache;
use think\Tree;
use common\model\DepartmentModel;
use common\model\MediaModel;
use common\model\OauthTokenModel;
use common\model\RoleModel;
use common\model\TenantModel;
use common\model\TenantUserModel;
use common\model\UserModel;

class UserService
{

    protected $jwtConfig;

    protected $jwtBuilder;

    protected $jwtParser;

    protected $jwtSha256;

    protected $jwtKey;

    // 单例工具类
    use SingletonTrait;

    /**
     * @var CentrifugalService
     */
    private $centrifugalService;

    public function __construct()
    {
        $this->centrifugalService = CentrifugalService::getInstance();
    }

    /**
     * 搜索租户下的用户
     * @param $tenantId
     * @param $param
     * @param bool $includeEmployed
     * @return array|false|mixed|string
     * @throws \Exception
     */
    public function searchTenantUser($tenantId, $param, bool $includeEmployed)
    {
        $where = [
            'tu.tenant_id' => $tenantId,
        ];
        if (!$includeEmployed) {
            $where['tu.status'] = ['NEQ', TenantUserModel::STATUS_UNEMPLOYED];
        }
        // 部门筛选
        if (!empty($param['filter']['department_id'])) {
            $departmentIds[] = $param['filter']['department_id'];
            $departmentIds = DepartmentService::getInstance()->getDepartmentUnderChildren($tenantId, $departmentIds);
            if (!empty($departmentIds)) {
                $where[] = [
                    "d.id" => ['IN', $departmentIds],
                ];
            }
        }

        if (!empty($param['filter']['name_or_phone'])) {
            $where[] = [
                'u.name' => $param['filter']['name_or_phone'],
                'u.phone' => $param['filter']['name_or_phone'],
                '_logic' => 'or',
            ];
        }
        if (!empty($param['filter']['specify_role'])) {
            $where['r.code'] = $param['filter']['specify_role'];
        }
        $adminRoleId = model(RoleModel::class)->where(['code' => 'admin'])->value('id');
        $where['r.id'] = ["neq", $adminRoleId]; //暂时去除掉管理员
        $res = $this->getUserDetailedInfo($where);
        $userIds = array_column($res, 'id');
        if (!empty($userIds)) {
            $avatarMap = $this->getUserAvatar($userIds);
            foreach ($res as &$user) {
                $user['avatar'] = $avatarMap[$user['id']] ?? null;
            }
        }
        return $res;
    }

    /**
     * 解析x-userinfo
     * @param $xUserInfoHeader
     * @return void
     * @throws \Exception
     */
    public function parseXUserInfoAndPresetRequest($xUserInfoHeader)
    {
        $request = \request();
        $XUserInfoBase = json_decode(base64_decode($xUserInfoHeader), true);
        if (!empty($XUserInfoBase) && !empty($XUserInfoBase['id'])) {

            $userDataIn = [
                'id' => $XUserInfoBase['id'],
                'phone' => $XUserInfoBase['phone'],
                'email' => $XUserInfoBase['email'],
                'name' => $XUserInfoBase['name'],
                'avatar' => !empty($XUserInfoBase['avatar']) ? $XUserInfoBase['avatar'] : "",
            ];
            $userCache = $request->getUserInfoCache($XUserInfoBase['id'], $userDataIn);
            if ($userCache !== false) {
                $userData = $userCache;
            } else {
                // 用户信息
                $userModel = model(UserModel::class);
                $userData = $userModel->field('id,phone,email,name,uuid')->where(['id' => $XUserInfoBase['id']])->find();
                $request->setUserInfoCache($XUserInfoBase['id'], $userData);
            }
            // 设置当前module code
            $controller = to_under_score($request->controller());

            $request->getModuleCode($controller);
            if (!empty($XUserInfoBase['tenant_id'])) {
                $request->getTenantId($XUserInfoBase['tenant_id']);
            }
            $request->getUserUUID($userData['uuid']);
            $request->getUserId($userData['id']);
            $request->getUnionUserId($XUserInfoBase['id']);
            $request->getXUserInfo($xUserInfoHeader);

            // 生成当前请求批次号
            $batchNumber = C('belong_system') . '_' . string_random(8) . '-' . create_uuid();
            $request->getBatchNumber($batchNumber);
        } else {
            // 错误的header头参数
            APP_DEBUG && trace("Wrong user info param.", "DEBUG");
            throw_strack_exception("Wrong user info param.", ErrorCode::WRONG_USER_INFO_PARAM);
        }
    }

    /**
     *  创建 token
     * @param $userData
     * @param $expire
     * @return string
     */
    protected function createToken($userData, $expire)
    {
        $time = time();
        $this->jwtBuilder->issuedBy($this->jwtConfig['domain'])
            ->permittedFor($this->jwtConfig['domain'])
            ->identifiedBy($this->jwtConfig['sign'], true)
            ->issuedAt($time)
            ->canOnlyBeUsedAfter($time + 60)
            ->expiresAt($time + $expire)// 一小时过期
            ->withClaim('id', $userData['id'])
            ->withClaim('phone', $userData['phone']);

        //获取加密后的token，转为字符串
        return (string)$this->jwtBuilder->getToken($this->jwtSha256, $this->jwtKey);
    }

    /**
     * 获取令牌
     * @param $userData
     * @return array
     * @throws \Exception
     */
    protected function getToken($userData)
    {
        //判断用户是否有权限（无激活）
        if ((int)$userData['active'] !== 1) {
            throw_strack_exception('no privileged user.', ErrorCode::OPERATION_WITHOUT_PERMISSION);
        }

        // 生成token
        $expires = time() + $this->jwtConfig['expire'];
        $refreshExpires = time() + $this->jwtConfig['refresh_expire'];
        $token = $this->createToken($userData, $expires);
        $refreshToken = $this->createToken($userData, $refreshExpires);

        $centrifugalToken = $this->centrifugalService->generateConnectionToken($userData, $expires);

        return [
            'access_token' => $token,
            'refresh_token' => $refreshToken,
            'centrifugal_token' => $centrifugalToken,
            'expires' => $expires,
        ];
    }

    /**
     * 按Key索引
     * @param $data
     * @param $key
     * @return array
     */
    protected function generateIndexByKey($data, $key)
    {
        $newData = [];
        foreach ($data as $item) {
            $newData[$item[$key]][] = $item;
        }
        return $newData;
    }

    /**
     * 查询当前用户基本信息
     * @param int $userId
     * @param int $tenantId
     * @return array
     * @throws \Exception
     */
    public function getInfo($userId, $tenantId = 0)
    {
        $resData = [];
        $resData['user'] = model(UserModel::class)->field('id,name,email,phone,sex,unionid,uuid,channel,is_identified')->find($userId);
        if (empty($resData['user'])) {
            throw new LogicException("user does not exist", ErrorCode::USER_NOT_EXIST);
        }
        if (empty($resData['user']['channel'])) {
            model(UserModel::class)->save([
                'channel' => md5($resData['user']['uuid']),
                'id' => $resData['user']['id'],
            ]);
        }
        unset($resData['user']['uuid']);
        $currentUserImage = model(MediaModel::class)
            ->field('thumb')
            ->where([
                'link_id' => $userId,
                'module' => 'user',
                'type' => 'thumb',
            ])
            ->cache('user_avatar_:' . $userId)
            ->find();
        $resData['user']['avatar'] = $currentUserImage['thumb'] ?? '';
        $tenantUserModel = model(TenantUserModel::class);
        $tenantModel = model(TenantModel::class);
        if ($tenantId) {
            $currentTenantUser = $tenantUserModel
                ->where(['user_id' => $userId, 'tenant_id' => $tenantId])
                ->where(['status' => ['NEQ', TenantUserModel::STATUS_UNEMPLOYED]])
                ->find();
        } else {
            $currentTenantUser = $tenantUserModel
                ->where(['tenant_user.user_id' => $userId, 'tenant_user.status' => 'active'])
                ->find();
        }
        $resData['tenant'] = $resData['tenant_position'] = null;
        $resData['department_info'] = $resData['role_info'] = [];

        if (empty($currentTenantUser)) {
            $currentTenantUser = $tenantUserModel
                ->where([
                    'user_id' => $userId,
                    'status' => 'invalid',
                ])
                ->order("id desc")->find();
            if (!empty($currentTenantUser)) {
                // 查询出第一家公司的所有信息 然后激活
                $tenantUserModel->where(['id' => $currentTenantUser['id']])->save(['status' => 'active']);
            }
        }

        if (!empty($currentTenantUser)) {
            $tenantJoinFields = [
                "tenant.id",
                "tenant.name",
                "tenant.created_by",
                "tenant.framework_agreement_contract_id",
                "tenant.framework_agreement_status",
                "tenant_authentication.status",
                "tenant_authentication.fdd_auth_status",
                "tenant_authentication.fdd_cert_status",
            ];
//            $tenantAuth = model(TenantAuthenticationModel::class)->where(['tenant_id' => $currentTenantUser['tenant_id'], 'status' => 'active'])->find();
            $resData['tenant'] = $tenantModel
                ->join("left join tenant_authentication on tenant.id = tenant_authentication.tenant_id")
                ->field($tenantJoinFields)
                ->where(['tenant.id' => $currentTenantUser['tenant_id'],])
                ->find();
//            $resData['tenant']['auth'] = empty($tenantAuth); // todo 2022年4月12日 暂时关闭 不然ue4无法启动
            // 岗位信息
            $resData['tenant_position'] = model(TenantPositionModel::class)->where(['id' => $currentTenantUser['tenant_position_id']])->field('id,name')->find();
            $userRoleDepartment = TenantUserService::getInstance()->getTenantUserListDepartmentRole([$currentTenantUser['id']]);
            $resData = array_merge($resData, $userRoleDepartment[$currentTenantUser['id']]);
        }
        return $resData;
    }

    /**
     * 通过用户信息生成登陆Token
     * @param $userData
     * @param $deviceUniqueCode
     * @param $ip
     * @return array
     * @throws \Exception
     */
    public function generateLoginTokenByUserData($userData, $deviceUniqueCode, $ip)
    {
        $userData['device_unique_code'] = $deviceUniqueCode;
        $tokenData = $this->getToken($userData);

        $oauthTokenModel = model(OauthTokenModel::class);

        if (!empty($tokenData)) {
            try {
                $existTokenId = $oauthTokenModel->where(['user_id' => $userData['id'], 'device_unique_code' => $deviceUniqueCode])
                    ->getField("id");

                $saveTokenData = [
                    'access_token' => md5($tokenData['access_token']),
                    'refresh_token' => md5($tokenData['refresh_token']),
                    'expires' => $tokenData['expires'],
                    'scope' => 'read,write',
                    'device_unique_code' => $deviceUniqueCode,
                    'ip' => $ip,
                ];

                if ($existTokenId > 0) {
                    $oauthTokenModel->where(['id' => $existTokenId])->save($saveTokenData);
                } else {
                    $saveTokenData['user_id'] = $userData['id'];
                    $oauthTokenModel->add($saveTokenData);
                }
            } catch (\Exception $e) {
                throw_strack_exception($e->getMessage(), ErrorCode::FAILED_TO_GENERATE_LOGIN_TOKEN);
            }
        }

        $resData = $this->getInfo($userData['id']);
        $resData['token'] = $tokenData;
        return $resData;
    }

    /**
     * 远端验证用户登陆
     * @param $param
     * @return array
     * @throws \Exception
     */
    public function remoteVerifyLoginByPassword($param)
    {
        $userModel = model(UserModel::class);

        $userData = $userModel->where([
            [
                "phone" => $param['login_name'],
                "email" => $param['login_name'],
                "_logic" => "OR",
            ],
            "active" => 1,
        ])->find();


        if (!empty($userData) && password_verify($param['password'], $userData['password'])) {
            // 验证密码
            return [
                "id" => $userData['id'],
                "name" => $userData['name'],
                "email" => $userData['email'],
                "phone" => $userData['phone'],
                "sex" => $userData['sex'],
                "password" => $param['password'],
            ];
        } else {
            // 账户不存在
            throw_strack_exception('user is not exist or password is wrong.', ErrorCode::USER_IS_NOT_EXIST_OR_PASSWORD_IS_WRONG);
        }
    }

    /**
     * 获取指定用户所在的租户
     * @param $userId
     * @return array
     */
    public function getUserAtTenant($userId)
    {
        $tenantUserModel = model(TenantUserModel::class);
        $userTenantIdData = $tenantUserModel->field('tenant_id')->where(['user_id' => $userId])->select();

        if (empty($userTenantIdData)) {
            return [];
        }
        return array_column($userTenantIdData, 'tenant_id');
    }

    /**
     * 判断当前租户id在当前用户租户id里面
     * @param $tenantId
     * @return bool
     */
    public function checkTenantIdInCurrentUser($tenantId)
    {
        $userId = \request()->getUserId();
        $userTenantIds = $this->getUserAtTenant($userId);

        if (in_array($tenantId, $userTenantIds)) {
            return true;
        }

        return false;
    }

    /**
     * 获取当前用户系统默认配置
     * @param $userId
     * @return array
     */
    public function getUserSystemConfig($userId)
    {
        $optionsService = new OptionsService();
        $resData = $optionsService->getOptionsData("default_settings");
        return ["lang" => $resData["default_lang"], "timezone" => $resData["default_timezone"], "mfa" => 'no'];
    }

    /**
     * 用户登陆
     * @param $param
     * @return array
     * @throws \Throwable
     */
    public function login($param)
    {
        switch ($param['mode']) {
            default:
            case 'phone':
                // 手机短信登陆
                return $this->loginBySMS($param);
            case 'password':
                // 账户密码登陆，账户支持手机号和邮箱
                return $this->loginByPassword($param);
            case "deviceCode":
                return $this->loginByDeviceCode($param);
            case "QRCodeId":
                // 通过二维码code id 登陆
                return $this->loginByQRCodeId($param);
        }
    }


    /**
     * 生成登陆授权数据
     * @param $oauthTokenData
     * @param $ip
     * @return array
     * @throws \Exception
     */
    protected function generateLoginAuthData($oauthTokenData, $ip)
    {
        /** @var UserModel $userModel */
        $userModel = model(UserModel::class);

        $userData = $userModel->where(['id' => $oauthTokenData['user_id']])->find();
        if (empty($userData)) {
            throw_strack_exception('Invalid token', ErrorCode::INVALID_TOKEN);
        }

        $tokenData = $this->getToken($userData);

        $saveTokenData = [
            'access_token' => md5($tokenData['access_token']),
            'refresh_token' => md5($tokenData['refresh_token']),
            'expires' => $tokenData['expires'],
            'ip' => $ip,
        ];

        $oauthTokenModel = model(OauthTokenModel::class);

        $saveTokenData['id'] = $oauthTokenData['id'];
        $oauthTokenModel->modifyItem($saveTokenData);

        $resData = $this->getInfo($userData['id']);
        $resData['token'] = $tokenData;

        return $resData;
    }


    /**
     * 注销登录
     * @param $token
     * @param $deviceCode
     * @return array
     */
    public function logout($token, $deviceCode)
    {

        $oauthTokenModel = model(OauthTokenModel::class);

        $count = $oauthTokenModel->where([
            'device_unique_code' => $deviceCode,
            'access_token' => md5($token),
        ])->count();
        if ($count == 0) {
            return [];
        }

        return $oauthTokenModel->where([
            'device_unique_code' => $deviceCode,
            'access_token' => md5($token),
            '_logic' => "OR",
        ])->delete();
    }

    /**
     * 短暂锁定同一个刷新令牌
     * @param $md5
     */
    protected function lockRefreshToken($md5)
    {
        $cache = S($md5);
        if (!empty($cache)) {
            if ($cache > time()) {
                throw_strack_exception('The same refresh token is locked for one minute.', ErrorCode::THE_SAME_REFRESH_TOKEN_IS_LOCKED_FOR_ONE_MINUTE);
            } else {
                S($md5, null);
            }
        }
    }

    /**
     * 刷新令牌
     * @param $param
     * @return array
     * @throws \Exception
     */
    public function refreshToken($param)
    {
        $deviceCode = $param['device_unique_code'];
        $refreshToken = $param['refresh_token'];
        $md5 = md5("{$refreshToken}_{$deviceCode}");

        // 1分钟内锁定 refresh_token
        $this->lockRefreshToken($md5);

        // 1.验证 refresh token 是否正确
        $oauthTokeModel = model(OauthTokenModel::class);
        $userTokenData = $oauthTokeModel->field('id,user_id')
            ->where([
                'refresh_token' => md5($refreshToken),
                'device_unique_code' => $deviceCode,
            ])
            ->find();

        if (empty($userTokenData)) {
            throw_strack_exception('Refresh token error.', ErrorCode::REFRESH_TOKEN_INVALID);
        }
        //解析token
        $parse = $this->jwtParser->parse($refreshToken);

        //验证token合法性
        if (!$parse->verify($this->jwtSha256, $this->jwtKey)) {
            throw_strack_exception('Invalid Refresh token', ErrorCode::REFRESH_TOKEN_INVALID);
        }

        //验证是否已经过期
        if ($parse->isExpired()) {
            throw_strack_exception('Refresh token has expired.', ErrorCode::REFRESH_TOKEN_HAS_EXPIRED);
        }

        $userModel = model(UserModel::class);
        $userData = $userModel->where(["id" => $userTokenData['user_id']])->find();
        $userData['device_unique_code'] = $deviceCode;
        $tokenData = $this->getToken($userData);

        $saveTokenData = [
            'access_token' => md5($tokenData['access_token']),
            'refresh_token' => md5($tokenData['refresh_token']),
            'expires' => $tokenData['expires'],
            'ip' => $param['ip'],
        ];
        $saveResData = $oauthTokeModel->where(['id' => $userTokenData['id']])->save($saveTokenData);
        if (!$saveResData) {
            throw new LogicException($oauthTokeModel->getError(), ErrorCode::ADD_OAUTH_TOKEN_FAILURE);
        }

        $resData = $this->getInfo($userData['id']);
        $resData['token'] = $tokenData;

        S($md5, time() + 60);
        return $resData;
    }


    /**
     * 获取用户头像
     * @param $userIds
     * @return array
     */
    public function getUserAvatar($userIds)
    {
        $mediaModel = model(MediaModel::class);
        $userAvatarList = $mediaModel->field('thumb,link_id as id')
            ->where([
                'link_id' => ['IN', implode(',', $userIds)],
                'module' => 'user',
                'type' => 'thumb',
            ])
            ->select();
        return array_column($userAvatarList, "thumb", 'id');
    }

    /**
     * 获取租户下的用户列表
     * @param $tenantId
     * @return mixed
     * @throws \Throwable
     */
    public function getTenantUserList($tenantId)
    {
        $res = model(TenantUserModel::class)
            ->join("user u ON tu.user_id = u.id")
            ->field("u.id,u.name,u.email,u.phone,tu.id tenant_user_id")
            ->where([
                'tu.tenant_id' => $tenantId,
            ])
            ->select();
        $userIds = array_column($res, 'id');

        if (!empty($userIds)) {
            $avatarMap = $this->getUserAvatar($userIds);
        }
        $tenantUserIdList = array_column($res, 'tenant_user_id');
        $tenantUserDepartmentRoleInfoList = TenantUserService::getInstance()->getTenantUserListDepartmentRole($tenantUserIdList);
        foreach ($res as &$user) {
            $user['avatar'] = $avatarMap[$user['id']] ?? null;
            $user['department_info'] = $user['role_info'] = [];
            if (isset($tenantUserDepartmentRoleInfoList[$user['tenant_user_id']])) {
                $user = array_merge($user, $tenantUserDepartmentRoleInfoList[$user['tenant_user_id']]);
            }
        }
        return $res;
    }

    /**
     * 获取租户下的部门的人员列表
     * @param $departmentId
     * @param int $tenantId
     * @param $includeEmployed
     * @return array
     * @throws \Exception
     */
    public function getTenantDepartmentUserList($departmentId, $tenantId, $includeEmployed)
    {
        $res = $this->getTenantDepartmentUserRow($departmentId, $tenantId, $includeEmployed);
        $userIds = array_column($res, 'id');
        if (!empty($userIds)) {
            $avatarMap = $this->getUserAvatar($userIds);
            foreach ($res as &$user) {
                $user['avatar'] = $avatarMap[$user['id']] ?? null;
            }
        }
        return $res;
    }

    /**
     * 获取租户下的部门的人员关联列表
     * @param $departmentId
     * @param int $tenantId
     * @param $includeEmployed
     * @return array
     * @throws \Exception
     */
    public function getTenantDepartmentUserRow($departmentId, $tenantId, $includeEmployed)
    {
        $where = [
            'd.id' => $departmentId,
            'u.is_system' => "no",
        ];
        if (!empty($tenantId)) {
            $where['tu.tenant_id'] = $tenantId;
        }
        if (!$includeEmployed) {
            $where['tu.status'] = ['NEQ', TenantUserModel::STATUS_UNEMPLOYED];
        }
        $rId = model(RoleModel::class)->where(['code' => 'admin'])->field('id')->find();
        $where['r.id'] = ["neq", $rId['id']]; //暂时去除掉管理员
        $field = $field ?? [
            'tu.id as tenant_user_id',
            'tu.user_id',
            "tp.id as tenant_position_id", "tp.name as tenant_position_name",
            'u.id', 'u.name', 'u.email', 'u.phone',
        ];
        $tenantUserList = model(TenantUserModel::class)
            ->alias('tu')
            ->join('tenant_position tp on tp.id = tu.tenant_position_id', 'LEFT')
            ->join("user u ON tu.user_id = u.id")
            ->join('tenant_user_department tud on tud.tenant_user_id = tu.id', 'LEFT')
            ->join('tenant_user_role tur on tur.tenant_user_id = tu.id', 'LEFT')
            ->join('department d on d.id = tud.department_id')
            ->join('role r on r.id = tur.role_id')
            ->field($field)
            ->group('tu.id')
            ->where($where)
            ->select();
        if (empty($tenantUserList)) {
            return [];
        }
        $departmentRoleInfoList = TenantUserService::getInstance()->getTenantUserListDepartmentRole(array_column($tenantUserList, 'tenant_user_id'));
        foreach ($tenantUserList as &$user) {
            $user['department_info'] = $user['role_info'] = [];
            if (isset($departmentRoleInfoList[$user['tenant_user_id']])) {
                $user = array_merge($user, $departmentRoleInfoList[$user['tenant_user_id']]);
            }
        }
        return $tenantUserList;
    }

    /**
     * 获取用户详细信息
     * @param $filter
     * @param null $field
     * @return array|false|mixed|string
     * @throws \Exception
     */
    public function getUserDetailedInfo($filter, $field = null)
    {
        $field = $field ?? [
            'tu.id as tenant_user_id',
            "u.id", "u.name", "u.email", "u.phone",
            "tp.id as tenant_position_id", "tp.name as tenant_position_name",
        ];

        $rows = model(TenantUserModel::class)
            ->alias('tu')
            ->join("user u ON tu.user_id = u.id")
            ->join("tenant_position tp on tu.tenant_position_id = tp.id", 'LEFT')
            ->join("tenant_user_department tud on tud.tenant_user_id = tu.id", 'LEFT')
            ->join("department d on d.id = tud.department_id", 'LEFT')
            ->join("tenant_user_role tur on tur.tenant_user_id = tu.id", 'LEFT')
            ->join("role r on r.id = tur.role_id", 'LEFT')
            ->field($field)
            ->where($filter)
            ->group('tu.id')
            ->select();
        $tenantUserIdList = array_column($rows, 'tenant_user_id');
        $departmentRoleInfoList = TenantUserService::getInstance()->getTenantUserListDepartmentRole($tenantUserIdList);

        foreach ($rows as &$row) {
            $row['department_info'] = $row['role_info'] = [];
            if (isset($departmentRoleInfoList[$row['tenant_user_id']])) {
                $row = array_merge($row, $departmentRoleInfoList[$row['tenant_user_id']]);
            }
        }
        return $rows;

    }

    /**
     * 获取租户下的部门的人员id
     * @param $departmentId
     * @param int $tenantId
     * @param $includeEmployed
     * @return array
     * @throws \Exception
     */
    public function getTenantDepartmentUserIds($departmentId, $tenantId, $includeEmployed)
    {
        $res = $this->getTenantDepartmentUserRow($departmentId, $tenantId, $includeEmployed);
        return array_column($res, 'id');
    }

    /**
     * 获取部门用户树
     * @param $tenantId
     * @return array
     * @throws \Throwable
     */
    public function getDepartmentTree($tenantId)
    {
        $departmentModel = model(DepartmentModel::class);

        $departmentData = $departmentModel
            ->where(["tenant_id" => $tenantId])
            ->field("id,name,parent_id")
            ->order(['id' => 'DESC'])
            ->select();

        $departmentUserCount = $departmentModel
            ->alias('d')
            ->join('tenant_user_department tud on tud.department_id = d.id')
            ->field("d.id,count(tud.id) AS user_count")
            ->order(['id' => 'DESC'])
            ->group("d.id")
            ->where(["d.tenant_id" => $tenantId])
            ->select();

        $departmentUserCount = array_column($departmentUserCount, 'user_count', 'id');
        $departmentUsers = $this->getTenantUserList($tenantId);
        $departmentUsers = array_group_by($departmentUsers, 'department_id');
        foreach ($departmentData as &$department) {
            $department['user_count'] = $departmentUserCount[$department['id']] ?? 0;
            $department['members'] = $departmentUsers[$department['id']] ?? [];
        }

        $tree = new Tree("id", "parent_id");
        $tree->load($departmentData);
        $departmentData = $tree->deepTree();
        $tree->traverseTree($departmentData, function (&$item) use ($departmentUserCount) {
            //因为是从末端开始遍历 遍历一层就可以
            $userCount = $item['user_count'];
            if (isset($item['children'])) {
                foreach ($item['children'] as $child) {
                    $userCount += $child['user_count'];
                }
            }
            $item['user_count'] = $userCount;
        });


        $res = [
            'children' => $departmentData,
            'members' => [],
        ];
        //没有部门用户和部门同级
        if (isset($departmentUsers[0])) {
            $res['members'] = $departmentUsers[0];
        }
        return $res;
    }

    /***
     * 查询用户列表
     * @param $param
     * @return array
     */
    public function selectUser($param)
    {
        try {
            $resData = [];

            //查询用户
            $userModel = model(UserModel::class);

            $param["fields"] = 'id,name,email,phone,sex,last_online_time,unionid,active';
            $param["order"] = ['created' => 'DESC'];
            $userData = $userModel->selectData($param);

            if ($userData["total"] === 0) {
                return ['rows' => [], 'total' => 0];
            }


            $userIds = array_column($userData['rows'], 'id');

            //查询用户头像
            $mediaModel = model(MediaModel::class);
            $userImages = $mediaModel->field('link_id,thumb')
                ->where([
                    'link_id' => ['IN', join(',', $userIds)],
                    'module' => 'user',
                    'type' => 'thumb',
                ])
                ->select();

            $userImageMap = $this->generateIndexByKey($userImages, 'link_id');
            foreach ($userData['rows'] as $value) {
                $resData[] = [
                    'id' => $value['id'],
                    'unionid' => $value['unionid'],
                    'name' => $value['name'],
                    'roles' => '',
                    'sex' => $value['sex'],
                    'phone' => $value['phone'],
                    'email' => $value['email'],
                    'active' => $value['active'],
                    'avatar' => $userImageMap[$value['id']][0]['thumb'] ?? '',
                ];
            }
            return ['rows' => $resData, 'total' => $userData['total']];
        } catch (\Exception $e) {
            throw_strack_exception($e->getMessage(), ErrorCode::FAILED_TO_QUERY_USER_INFO);
        }
    }

    /**
     * 添加用户
     * @param $data
     * @param bool $returnExist
     * @return array|bool
     * @throws \Exception
     */
    public function addUser($data, $returnExist = false)
    {
        $userModel = model(UserModel::class);
        $resData = $userModel->addItem($data);
        if (!$resData) {
            $errorCode = !empty($userModel->getErrorCode()) ? $userModel->getErrorCode() : -202012;
            if ($returnExist && $errorCode === -411111) {
                // 已经存在数据
                return $userModel->getCheckUniqueExitData();
            } else {
                throw_strack_exception($userModel->getError(), ErrorCode::FAILED_TO_CREATE_USER);
            }
        }
        return $resData;
    }

    /**
     * 注册用户
     * @param $param
     * @return array|bool
     * @throws \Exception
     */
    public function register($param)
    {
        // 验证短信验证码
        $smsService = new SMSService();
        if (!$smsService->verifySMSCode('register', $param['data']['phone'], $param['sms_code'])) {
            throw_strack_exception('Invalid SMS verification code.', ErrorCode::SMS_VERIFICATION_CODE_ERROR);
        }

        return $this->addUserWithMedia($param);
    }

    /**
     * 后台添加用户（同时上传头像）
     * @param $param
     * @param bool $returnExist
     * @return array|bool
     * @throws \Exception
     */
    public function addUserWithMedia($param, $returnExist = false)
    {
        if (empty($param['data']['email'])) {
            $param['data']['email'] = $param['data']['phone'] . '@teamones.com';
        }

        $param['data']['channel'] = $param['data']['channel'] ?? "";
        $userAddResData = $this->addUser($param['data'], $returnExist);


        // 添加媒体
        if (isset($param['media'])
            && !empty($param['media'])
            && !empty($param['media']['type'])
            && !empty($param['media']['media_server'])
            && !empty($param['media']['media_data'])
        ) {
            $mediaData = $param['media'];
            $mediaData['module'] = 'user';
            $mediaData['link_id'] = (string)$userAddResData['id'];
            $mediaService = new MediaService();
            $mediaAddData = $mediaService->upload($mediaData);
            $userAddResData['avatar'] = $mediaAddData[0]['thumb'];
        } else {
            $userAddResData['avatar'] = '';
        }

        return $userAddResData;
    }

    /**
     * 修改用户
     * @param $param
     * @return array|bool
     * @throws \Exception
     */
    public function modifyUser($param)
    {
        $userModel = model(UserModel::class);
        $userId = $userModel->where($param['filter'])->getField("id");

        if ($userId >= 0) {
            $param['data']['id'] = $userId;
            $resData = $userModel->modifyItem($param['data']);

            if (!$resData) {
                if ($userModel->getErrorCode() === -411112) {
                    return ['id' => $userId];
                } else {
                    throw new LogicException($userModel->getError(), $userModel->getErrorCode());
                }
            }

            return $resData;
        } else {
            throw_strack_exception('Failed to modify user.', ErrorCode::FAILED_TO_MODIFY_USER);
        }
    }

    /**
     * 后台修改用户（同时修改头像）
     * @param $param
     * @return array|bool
     * @throws \Exception
     */
    public function modifyUserWithMedia($param)
    {
        if (isset($param['data']['phone'])) {
            // 手机号不能修改
            unset($param['data']['phone']);
        }

        $resData = $this->modifyUser($param);

        if (!empty($param['media'])
            && !empty($param['media']['type'])
            && !empty($param['media']['media_server'])
            && !empty($param['media']['media_data'])
        ) {
            $mediaData = $param['media'];
            $mediaData['module'] = 'user';
            $mediaData['link_id'] = (string)$resData['id'];
            $mediaService = new MediaService();
            $mediaAddData = $mediaService->upload($mediaData);
            $resData['avatar'] = $mediaAddData[0]['thumb'];
            Cache::rm("user_avatar_:" . $resData['id']);
        } else {
            $resData['avatar'] = '';
        }

        return $resData;
    }

    /**
     * 修改用户密码(登录后)
     * @param $userId
     * @param $param
     * @return array
     * @throws \Exception
     */
    public function modifyUserPassword($userId, $param)
    {
        $userModel = model(UserModel::class);

        // 用户是否存在
        $userData = $userModel->field('id,password')->where(["id" => $userId])->find();

        if (!empty($userData)) {
            //验证原密码是否一致
            if (password_verify($param['old_password'], $userData['password'])) {

                // 更新数据库password
                $modifyData = [
                    "id" => (int)$userData['id'],
                    'password' => $param['new_password'],
                ];

                $result = $userModel->modifyItem($modifyData);

                if (!$result) {
                    $errCode = $userModel->getErrorCode();
                    if (empty($errCode)) {
                        $errCode = -41009;
                    }
                    throw_strack_exception($userModel->getError(), $errCode);
                }
                return [];
            } else {
                throw_strack_exception('Wrong phone number or password.', ErrorCode::USER_IS_NOT_EXIST_OR_PASSWORD_IS_WRONG);
            }
        } else {
            throw_strack_exception('User does not exist.', ErrorCode::USER_NOT_EXIST);
        }
    }

    /**
     * 删除用户信息
     * @param $param
     * @return array
     */
    public function deleteUser($param)
    {
        $userModel = model(UserModel::class);
        $mediaModel = model(MediaModel::class);

        // 判断当前用户是否存在
        $userData = $userModel->field('id')->where($param['filter'])->find();

        if (!empty($userData)) {
            try {
                //查询用户头像
                $filter = [
                    'link_id' => $userData['id'],
                    'module' => 'user',
                    'type' => 'thumb',
                ];
                $avatar = $mediaModel->field('link_id,thumb')->where($filter)->find();
                if (!empty($avatar)) {
                    $mediaModel->where($filter)->delete();
                }
                $userModel->where($param['filter'])->delete();
                return [];
            } catch (\Exception $e) {
                throw_strack_exception($e->getMessage(), ErrorCode::FAILED_TO_DELETE_USER);
            }
        } else {
            throw_strack_exception('User does not exist.', ErrorCode::USER_NOT_EXIST);
        }
    }

    /**
     * 切换用户激活状态
     * @param $param
     * @return array
     * @throws \Exception
     */
    public function switchActiveUser($param)
    {
        $userModel = model(UserModel::class);

        //用户是否存在
        $userData = $userModel->field('id,active')->where($param['filter'])->find();
        if (empty($userData)) {
            throw_strack_exception('User does not exist.', ErrorCode::USER_NOT_EXIST);
        }
        $active = 1;
        if ($userData['active'] == 1) {
            $active = 0;
        }
        //修改用户激活状态
        $userModel->where($param['filter'])->setField('active', $active);

        //注销后的操作
        $this->switchActiveUserChat($active, $userData['id']);

        return [];
    }

    /**
     * 注销用户后离开聊天会话
     * @param $isActive
     * @param $userId
     * @return bool|int|string
     * @throws \Exception
     */
    public function switchActiveUserChat($isActive, $userId)
    {
        $isLeave = [];
        $one2oneChatDelete = [];
        if ($isActive) {
            $isLeave['is_leave'] = 'yes';
            $one2oneChatDelete['is_delete'] = 'yes';
        } else {
            $isLeave['is_leave'] = 'no';
            $one2oneChatDelete['is_delete'] = 'no';
        }


        $currentUserChat = model(ChatUserModel::class)
            ->join('chat on chat_user.chat_global_id = chat.global_id')
            ->where(['user_id' => $userId])
            ->field('chat_user.id,chat_user.chat_global_id,chat.type')->select();

        $one2oneChatId = [];
        $otherChatUserId = [];
        $count = 0;
        if (!empty($currentUserChat)) {
            foreach ($currentUserChat as $currentUserChatItem) {
                if ($currentUserChatItem['type'] === 'one2one') {
                    $one2oneChatId[] = $currentUserChatItem['chat_global_id'];
                } else {
                    $otherChatUserId[] = $currentUserChatItem['id'];
                }
            }

            //一对一会话更新
            if (!empty($one2oneChatId)) {
                $count = model(ChatUserModel::class)->where(['chat_global_id' => ['IN', $one2oneChatId]])->save($isLeave);
                model(ChatModel::class)->where(['global_id' => ['IN', $one2oneChatId]])->save($one2oneChatDelete);
            }

            //在其他群里离开
            if (!empty($otherChatUserId)) {
                model(ChatUserModel::class)->where(['id' => ['IN', $otherChatUserId]])->save($isLeave);
            }
        }
        return $count;
    }

    /**
     * 获得其他用户信息 list
     * @param $param
     * @param int $tenantId
     * @return mixed
     * @throws \Throwable
     */
    public function getOtherUsersInfo($param, int $tenantId)
    {
        $userModel = model(UserModel::class);
        $tenantUserModel = model(TenantUserModel::class);
        $userList = $userModel->where($param['filter'])
            ->field('id,name,email,phone,sex,last_online_time,unionid')->select();

        $userIds = array_column($userList, 'id', 'id');
        $avatars = $this->getUserAvatar($userIds);

        $tenantUsersQueryFields = [
            'tenant_user.id',
            'tenant_user.tenant_id',
            'tenant_user.user_id',
            'tenant_user.tenant_position_id',
            'tenant.name as tenant_name',
        ];
        $tenantUsersFilter = [
            'tenant_user.user_id' => ["IN", implode(',', $userIds)],
            'tenant_user.status' => 'active',
        ];
        if ($tenantId > 0) {
            $tenantUsersFilter['tenant_user.tenant_id'] = $tenantId;
            unset($tenantUsersFilter['tenant_user.status']);
        }
        $tenantUsers = $tenantUserModel
            ->Join("tenant ON tenant_user.tenant_id = tenant.id")
            ->where($tenantUsersFilter)
            ->field($tenantUsersQueryFields)
            ->select();
        $userTenantUserMap = array_column($tenantUsers, null, 'user_id');
        $tenantUserIdList = array_column($tenantUsers, 'id');
        $positionIdMap = array_column($tenantUsers, 'tenant_position_id', 'tenant_position_id');
        $tenantUserDepartmentRoleInfoList = TenantUserService::getInstance()->getTenantUserListDepartmentRole($tenantUserIdList);
        // 查询岗位信息
        $positionList = [];
        if (count($positionIdMap) > 0) {
            $positionList = model(TenantPositionModel::class)->where(['id' => ['IN', array_values($positionIdMap)]])->field('id,name')->select();
            $positionList = array_column($positionList, null, 'id');
        }

        $res = $userList;
        foreach ($res as &$userInfo) {
            $tenantUser = $userTenantUserMap[$userInfo['id']] ?? 0;
            $userInfo['avatar'] = $avatars[$userInfo['id']] ?? null;
            $userInfo = [
                'user' => $userInfo,
                'tenant' => null,
                'role' => null,
                'department_info' => [],
                'role_info' => [],
                'tenant_position' => null,
            ];
            if (empty($tenantUser)) {
                continue;
            }
            $userInfo['tenant']['id'] = $tenantUser['tenant_id'];
            $userInfo['tenant']['name'] = $tenantUser['tenant_name'];

            if ($tenantUser['tenant_position_id'] && isset($positionList[$tenantUser['tenant_position_id']])) {
                $userInfo['tenant_position'] = $positionList[$tenantUser['tenant_position_id']];
            }
            if (!isset($tenantUserDepartmentRoleInfoList[$tenantUser['id']])) {
                continue;
            }
            $userInfo = array_merge($userInfo, $tenantUserDepartmentRoleInfoList[$tenantUser['id']]);
            if (!empty($userInfo['role_info'])) {
                $userInfo['role'] = $userInfo['role_info'][0];
            }
        }
        return $res;
    }

    /**
     * 清除当前用户 指定设备码的登录信息
     * @param int $userId
     * @param string $deviceUniqueCode
     * @return false|int|mixed|string
     */
    public function clearTokenByDeviceCode(int $userId, string $deviceUniqueCode)
    {
        return model(OauthTokenModel::class)
            ->where([
                'user_id' => $userId,
                'device_unique_code' => $deviceUniqueCode,
            ])
            ->delete();
    }

    /**
     * 获得用户fdd_customer_id
     * @param $filter
     * @return mixed
     */
    public function getFddCustomerId($filter)
    {
        $user = model(UserModel::class)->where($filter)->find();
        if (empty($user)) {
            throw_strack_exception('user does not exist.', ErrorCode::USER_NOT_EXIST);
        }
        if (empty($user['fdd_customer_id'])) {
            throw_strack_exception("missing fdd_customer_id", ErrorCode::MISSING_FDD_CUSTOMER_ID);
        }
        return $user['fdd_customer_id'];
    }

    /**
     * 查询系统用户信息
     * @param $param
     * @param $tenantId
     * @return array
     * @throws \Exception
     */
    public function selectSystemUser($param, $tenantId)
    {
        $page = $param['page'] ?? [1, C("database.database_max_select_rows")];
        $order = $param['order'] ?? "user.id DESC";
        $where = $param['filter'] ?? [];
        $where['user.is_system'] = "yes";
        $where['user.phone'] = ['NEQ', 'admin'];

        $fields = $param['fields'] ?? null;
        if (empty($fields)) {
            $fields = [
                "user.id",
                "user.name",
                "user.email",
                "user.phone",
                "user.status",
                "user.created",
                "user.is_system",
                "tenant_user.id",
                "tenant_user.tenant_id",
                "tenant_user.user_id",
                "tenant_robot_user_certificate.id",
                "tenant_robot_user_certificate.app_key",
                "tenant_robot_user_certificate.app_secret",
                "tenant_robot_user_certificate.active",
                "tenant_robot_user_certificate.uuid",
            ];
            $fields = build_complex_query_fields($fields, "__");
            $fields = implode(',', $fields);
        }
        $count = model(UserModel::class)
            ->join("tenant_user ON tenant_user.user_id = user.id AND tenant_user.tenant_id={$tenantId}", 'LEFT')
            ->join('tenant_user_department on tenant_user_department.tenant_user_id = tenant_user.id', 'LEFT')
            ->join('tenant_user_role on tenant_user_role.tenant_user_id = tenant_user.id', 'LEFT')
            ->join("department ON tenant_user_department.department_id = department.id", "LEFT")
            ->join('role ON role.id = tenant_user_role.role_id', "LEFT")
            ->join('tenant_robot_user_certificate ON tenant_user.id = tenant_robot_user_certificate.tenant_user_id', 'LEFT')
            ->where($where)
            ->count();
        $rows = model(UserModel::class)
            ->join("tenant_user ON tenant_user.user_id = user.id AND tenant_user.tenant_id={$tenantId}", 'LEFT')
            ->join('tenant_user_department on tenant_user_department.tenant_user_id = tenant_user.id', 'LEFT')
            ->join('tenant_user_role on tenant_user_role.tenant_user_id = tenant_user.id', 'LEFT')
            ->join("department ON tenant_user_department.department_id = department.id", "LEFT")
            ->join('role ON role.id = tenant_user_role.role_id', "LEFT")
            ->join('tenant_robot_user_certificate ON tenant_user.id = tenant_robot_user_certificate.tenant_user_id', 'LEFT')
            ->where($where)
            ->field($fields)
            ->order($order)
            ->page($page[0], $page[1])
            ->group('user.id')
            ->select();
        $tenantUserIdList = array_column($rows, 'tenant_user__id');
        $tenantUserDepartmentRoleList = TenantUserService::getInstance()->getTenantUserListDepartmentRole($tenantUserIdList);
        foreach ($rows as &$row) {
            $row = separate_complex_query_data($row, "__");
            $row['department_info'] = $row['role_info'] = [];
            if (isset($tenantUserDepartmentRoleList[$row['tenant_user']['id']])) {
                $row = array_merge($row, $tenantUserDepartmentRoleList[$row['tenant_user']['id']]);
            }
        }
        return ['total' => $count, 'rows' => $rows];
    }

    /**
     * 普通用户查询
     * @param $param
     * @return array
     * @throws \Exception
     */
    public function selectNormalUser($param)
    {
        $param['filter']['is_system'] = 'no';
        return model(UserModel::class)->selectData($param);
    }

    /**
     * 获取当前用户的部门
     * @param $tenantId
     * @param $userId
     * @return array|false|mixed|string
     */
    public function getCurrentDepartment($tenantId, $userId)
    {
        return model(TenantUserModel::class)
            ->join('tenant_user_department on tenant_user_department.tenant_user_id = tenant_user.id')
            ->join("department ON tenant_user_department.department_id = department.id")
            ->where(['tenant_user.user_id' => $userId, 'tenant_user.tenant_id' => $tenantId])
            ->field('department.id,department.name')
            ->select();
    }

    /**
     * 获取部门的子集及其用户
     * @param $tenantId
     * @param $param
     * @param $includeEmployed
     * @return array
     * @throws \Exception
     */
    public function getChildrenDepartmentUser($tenantId, $param, $includeEmployed)
    {
        $departmentModel = model(DepartmentModel::class);

        $departmentData = $departmentModel
            ->where(["tenant_id" => $tenantId])
            ->field("id,name,parent_id")
            ->order(['id' => 'DESC'])
            ->select();

        $rId = model(RoleModel::class)->where(['code' => 'admin'])->field('id')->find();
        $departmentUserCountFilter = [
            "tenant_user.tenant_id" => $tenantId,
            'u.is_system' => "no",
            'tenant_user_role.role_id' => ["neq", $rId['id']],
        ];
        if (!$includeEmployed) {
            $departmentUserCountFilter['tenant_user.status'] = ['NEQ', TenantUserModel::STATUS_UNEMPLOYED];
        }
        $departmentUserCount = model(TenantUserModel::class)
            ->join("user u ON tenant_user.user_id = u.id")
            ->join('tenant_user_department on tenant_user.id = tenant_user_department.tenant_user_id')
            ->join('tenant_user_role on tenant_user.id = tenant_user_role.tenant_user_id', 'LEFT')
            ->join("role r on r.id = tenant_user_role.role_id", 'LEFT')
            ->field("tenant_user_department.department_id,count(distinct tenant_user.id) AS user_count")
            ->where($departmentUserCountFilter)
            ->order('tenant_user_department.department_id DESC')
            ->group("tenant_user_department.department_id")
            ->select();

        $departmentUserCount = array_column($departmentUserCount, 'user_count', 'department_id');
        foreach ($departmentData as &$department) {
            $department['user_count'] = $departmentUserCount[$department['id']] ?? 0;
        }

        $currentDepartmentId = 0;
        $currentDepartment = null;
        if (!empty($param['filter'])) {
            $currentDepartment = $departmentModel->where($param['filter'])->find();
            if (!empty($currentDepartment)) {
                $currentDepartmentId = $currentDepartment['id'];
            }
        }
        $departmentUsers = $this->getTenantDepartmentUserList($currentDepartmentId, $tenantId, $includeEmployed);
        /** @var Tree $tree */
        $tree = new Tree("id", "parent_id");
        $tree->load($departmentData);
        $departmentData = $tree->deepTree($currentDepartmentId);

        $tree->traverseTree($departmentData, function (&$item) use ($departmentUserCount) {
            //因为是从末端开始遍历 遍历一层就可以
            $userCount = $item['user_count'];
            if (isset($item['children'])) {
                foreach ($item['children'] as $child) {
                    $userCount += $child['user_count'];
                }
            }
            $item['user_count'] = $userCount;
        });

        foreach ($departmentData as &$departmentDataItem) {
            $departmentDataItem['type'] = 'department';
            unset($departmentDataItem['children']);
        }

        $res = [
            'children' => $departmentData,
            'members' => [],
        ];
        //没有部门用户和部门同级
        if (!empty($departmentUsers)) {
            $departmentUsers = array_map(function ($item) use ($currentDepartment) {
                $item['department_name'] = empty($currentDepartment) ? '' : $currentDepartment['name'];
                return $item;
            }, $departmentUsers);
            $res['members'] = $departmentUsers;
        }
        return $res;
    }

    /**
     * 获取用户的群组
     * @param $userId
     * @return array
     */
    public function getCurrentChatGroup($userId)
    {
        $chatList = model(ChatUserModel::class)
            ->join("LEFT join chat on chat.global_id = chat_user.chat_global_id")
            ->join("chat_user as cu on chat_user.chat_global_id = cu.chat_global_id")
            ->field("chat.id,chat.global_id,chat.`name`,chat.link_type,COUNT(cu.user_id) as user_count")
            ->where([
                "chat_user.user_id" => $userId,
                "chat.type" => 'group',
                'chat_user.is_leave' => 'no',
                'chat.is_delete' => 'no',
            ])
            ->group("chat_user.chat_global_id")
            ->select();

        $chatGlobalIds = array_column($chatList, 'global_id');
        $chatList = array_column($chatList, null, 'global_id');


        $chatUserData = model(ChatUserModel::class)
            ->where([
                'chat_global_id' => ['IN', join(',', $chatGlobalIds)],
                'is_leave' => "no",
            ])
            ->field("GROUP_CONCAT(distinct user_id) as user_ids,chat_global_id")
            ->group("chat_global_id")
            ->select();

        if (!empty($chatUserData)) {
            $chatUserIds = [];

            $chatUserData = array_map(function ($item) use (&$chatUserIds) {
                $userIds = explode(',', $item['user_ids']);
                $arraySlice = array_slice($userIds, 0, 9);
                if (count($userIds)) {
                    if (empty($chatUserIds)) {
                        $chatUserIds = $arraySlice;
                    } else {
                        $chatUserIds = array_merge($chatUserIds, $arraySlice);
                    }
                }
                $item['user_ids'] = $arraySlice;
                return $item;
            }, $chatUserData);
            $chatUserData = array_column($chatUserData, 'user_ids', 'chat_global_id');
            $chatUserIds = array_unique($chatUserIds);
            $userInfo = model(UserModel::class)
                ->alias('user')
                ->join('LEFT JOIN media ON media.link_id=user.id AND media.type="thumb" AND media.module="user"')
                ->field('user.id,user.name,media.thumb,media.thumb as avatar')
                ->where(['user.id' => ['IN', join(',', $chatUserIds)]])
                ->select();

            $userInfoMap = array_column($userInfo, null, 'id');

            $chatAvatar = [];
            foreach ($chatUserData as $chatGlobalId => $userIds) {
                foreach ($userIds as $userId) {
                    $chatAvatar[$chatGlobalId]['chat_icon_data'][] = [
                        "name" => $userInfoMap[$userId]['name'] ?? "",
                        "avatar" => $userInfoMap[$userId]['thumb'] ?? "",
                    ];
                }
            }


            foreach ($chatList as $chatListId => &$chatListItem) {
                $chatListItem['chat_icon_data'] = $chatAvatar[$chatListId]['chat_icon_data'];
            }

            $chatList = array_values($chatList);
        }


        return $chatList;
    }

    /**
     * 常用联系人
     * @param $filter
     * @param $currentUserId
     * @param int $limit
     * @return array
     */
    public function frequentContacts($filter, $currentUserId, $limit = 50)
    {
        if (!empty($filter['sent_at'])) {
            $frequentContactsFilter['last_message_send_at'] = $filter['sent_at'];
        } else { //默认一周之内
            $frequentContactsFilter['last_message_send_at'] = ['egt', strtotime('-7 days')];
        }

        $frequentContactsFilter['user_id'] = $currentUserId;

        $frequentContacts = model(FrequentContactsModel::class)
            ->where($frequentContactsFilter)
            ->limit($limit)
            ->field('link_user_id,chat_global_id')
            ->order('last_message_send_at desc')
            ->select();

        $linkUserIds = array_column($frequentContacts, 'link_user_id');
        $frequentContacts = array_column($frequentContacts, null, 'link_user_id');

        if (empty($linkUserIds)) {
            return [];
        }
        $linkUserFilter = [
            'user.id' => ['IN', $linkUserIds],
        ];

        //按租户ID--获取最近联系人
        if (!empty($filter['tenant_id'])) {
            $linkUserFilter['user.is_system'] = UserModel::IS_SYSTEM_NO;
            $linkUserFilter['tenant_user.tenant_id'] = $filter['tenant_id'];
        }

        $linkUserList = model(UserModel::class)
            ->join('tenant_user on tenant_user.user_id = user.id')
            ->join('tenant on tenant_user.tenant_id = tenant.id')
            ->where($linkUserFilter)
            ->field('user.id,user.name,tenant.name as tenant_name,tenant_user.status')
            ->select();

        $linkUserList = array_filter($linkUserList, function ($linkUserListItem) {
            return $linkUserListItem['status'] === 'active';
        });
        $linkUserList = array_values($linkUserList);

        $userIds = array_column($linkUserList, 'id');
        if (!empty($userIds)) {
            $avatarMap = $this->getUserAvatar($userIds);
            foreach ($linkUserList as &$userItem) {
                $userItem['chat_global_id'] = $frequentContacts[$userItem['id']]['chat_global_id'];
                $userItem['avatar'] = $avatarMap[$userItem['id']] ?? null;
                unset($userItem['status']);
            }
        }

        return $linkUserList;
    }

    /**
     * 更新用户联系人
     * @param $chatGlobalId
     * @param $sentAt
     * @throws \Exception
     */
    public function saveFrequentContactsConsumer($chatGlobalId, $sentAt)
    {
        $oneChatUser = model(ChatUserModel::class)->where(['chat_global_id' => $chatGlobalId])->field('user_id')->select();
        $oneChatUserIds = array_column($oneChatUser, 'user_id');

        $chatMessageSendAtKey = "chat_last_message_send_at:chat_{$chatGlobalId}";
        $chatMessageSendAt = Cache::get($chatMessageSendAtKey);

        //更新联系人表
        if (!empty($chatMessageSendAt)) {
            return;
        }
        Cache::set($chatMessageSendAtKey, $sentAt, 300); //5分钟更新一次
        $dataUser = ['chat_global_id' => $chatGlobalId, 'user_id' => $oneChatUserIds[0], 'link_user_id' => $oneChatUserIds[1]];
        //更新用户的联系
        $frequentContactsUser = model(FrequentContactsModel::class)->where($dataUser)->field('id')->find();
        $dataUser['last_message_send_at'] = $sentAt;
        if (!empty($frequentContactsUser)) {
            $dataUser['id'] = $frequentContactsUser['id'];
            model(FrequentContactsModel::class)->save($dataUser);
        } else {
            model(FrequentContactsModel::class)->addItem($dataUser);
        }

        //更新用户会话关联的用户的联系人
        $dataLinkUser = ['chat_global_id' => $chatGlobalId, 'user_id' => $oneChatUserIds[1], 'link_user_id' => $oneChatUserIds[0]];
        $frequentContactsLinkUser = model(FrequentContactsModel::class)->where($dataLinkUser)->field('id')->find();
        $dataLinkUser['last_message_send_at'] = $sentAt;
        if (!empty($frequentContactsLinkUser)) {
            $dataLinkUser['id'] = $frequentContactsLinkUser['id'];
            model(FrequentContactsModel::class)->save($dataLinkUser);
        } else {
            model(FrequentContactsModel::class)->addItem($dataLinkUser);
        }
    }


    /**
     * 获取他人用户信息
     * @param $userId
     * @param bool $hide
     * @return array
     * @throws \Exception
     */
    public function getOtherUserInfo($userId, $hide = true)
    {
        $resData = $this->getInfo($userId);
        if (isset($resData['user']) && $hide) {
            $resData['user']['phone'] = '';
            $resData['user']['email'] = '';
        }
        return $resData;
    }

    /**
     * 获得系统通知用户信息
     * @param string $notifyUserMark
     * @return mixed
     * @throws \Exception
     */
    public function getSystemNoticeUser($notifyUserMark = "")
    {
        if ($notifyUserMark === "") {
            return model(UserModel::class)->where(['is_system' => 'yes'])->select();
        }

        switch ($notifyUserMark) {
            case "tool_man_assistant":
                $configName = "tool_man_assistant_notify_message_user_id";
                break;
            case 'work_order_assistant':
                $configName = 'work_order_assistant_notify_message_user_id';
                break;
            case 'ai_assistant':
                $configName = 'ai_assistant_notify_message_user_id';
                break;
            case "producer_assistant":
            default:
                $configName = 'default_notify_message_user_id';

        }
        $notifyUserId = OptionsService::getInstance()->getOptionsConfigItemData("default_settings", $configName);
        return model(UserModel::class)->find((int)$notifyUserId);
    }

    /**
     * 通过手机号,获取用户id
     * @param $data
     * @return array|false|mixed|string
     */
    public function getUserId($data)
    {
        return model(UserModel::class)->field('phone,id')->where(['phone' => ['IN', $data['mobile_list']]])->select();
    }

    /**
     * 获取指定role下的租户成员列表
     * @param $tenantId
     * @param $param
     * @param $includeEmployed
     * @return array|false|mixed|string
     * @throws \Exception
     */
    public function getSpecifyRoleUser($tenantId, $param, $includeEmployed)
    {
        $specifyRole = $param['filter']['specify_role'];
        $rIds = model(RoleModel::class)->where(['code' => $specifyRole])->field('id')->column("id");
        $fields = [
            "u.id", "u.name", "u.email", "u.phone",
        ];
        $specifyRoleUserListFilter = [
            "tu.tenant_id" => $tenantId,
            'u.is_system' => "no",
            'tenant_user_role.role_id' => ['IN', $rIds],
        ];
        if (!$includeEmployed) {
            $specifyRoleUserListFilter['tu.status'] = ['NEQ', TenantUserModel::STATUS_UNEMPLOYED];
        }
        $specifyRoleUserList = model(UserModel::class)->alias('u')
            ->join("tenant_user tu ON tu.user_id = u.id")
            ->join('tenant_user_role on tenant_user_role.tenant_user_id = tu.id')
            ->join("role r on r.id = tenant_user_role.role_id")
            ->field($fields)
            ->where($specifyRoleUserListFilter)
            ->group("u.id")
            ->field('tu.id tenant_user_id,u.id')
            ->select();
        $userIds = array_column($specifyRoleUserList, 'id');
        $tenantUserIdMap = array_column($specifyRoleUserList, 'tenant_user_id', 'id');
        if (empty($userIds)) {
            return [];
        }
        $userList = model(UserModel::class)
            ->where(['id' => ['IN', implode(',', $userIds)]])
            ->field('id,name,email,phone')
            ->select();
        $avatarMap = $this->getUserAvatar($userIds);
        $userDepartmentRoleInfoList = TenantUserService::getInstance()->getTenantUserListDepartmentRole(array_column($specifyRoleUserList, 'tenant_user_id'));
        foreach ($userList as &$user) {
            $tenantUserId = $tenantUserIdMap[$user['id']];
            $user['avatar'] = $avatarMap[$user['id']] ?? null;
            $user['department_info'] = $user['role_info'] = [];
            if (isset($userDepartmentRoleInfoList[$tenantUserId])) {
                $user = array_merge($user, $userDepartmentRoleInfoList[$tenantUserId]);
            }
        }

        return $userList;
    }
}
